package logger

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"

	"github.com/fatih/color"
)

// LogLevel 表示日志级别
type LogLevel int

const (
	DEBUG LogLevel = iota
	INFO
	WARN
	ERROR
	FATAL
)

var levelNames = map[LogLevel]string{
	DEBUG: "DEBUG",
	INFO:  "INFO",
	WARN:  "WARN",
	ERROR: "ERROR",
	FATAL: "FATAL",
}

var levelPrefix = map[LogLevel]string{
	DEBUG: color.New(color.FgWhite).Sprintf("DEBUG"),   // 白色，适合调试信息
	INFO:  color.New(color.FgGreen).Sprintf("INFO"),    // 绿色，表示正常的信息
	WARN:  color.New(color.FgYellow).Sprintf("WARN"),   // 黄色，表示警告
	ERROR: color.New(color.FgRed).Sprintf("ERROR"),     // 红色，表示错误
	FATAL: color.New(color.FgMagenta).Sprintf("FATAL"), // 品红色，表示致命错误
}

// Logger 结构体包含了日志记录器的所有配置
type Logger struct {
	level       LogLevel
	logger      *log.Logger
	stackLogger *log.Logger
	mu          sync.Mutex
	file        *os.File
	stackFile   *os.File
	fileOutput  bool
	filePrefix  string
	currentDay  int
	logPath     string
}

// Config 包含了创建Logger所需的所有配置
type Config struct {
	Level      LogLevel
	LogPath    string
	FilePrefix string
	FileOutput bool
}

// NewLogger 创建一个新的日志记录器
func NewLogger(config Config) (*Logger, error) {
	logger := &Logger{
		level:      config.Level,
		fileOutput: config.FileOutput,
		filePrefix: config.FilePrefix,
		logPath:    config.LogPath,
		currentDay: -1,
	}

	err := os.MkdirAll(logger.logPath, 0755)
	if err != nil {
		return nil, fmt.Errorf("无法创建日志目录: %v", err)
	}

	if config.FileOutput {
		err := logger.rotateFile()
		if err != nil {
			return nil, err
		}
	}

	// 初始化 stack.log 文件
	stackFilePath := filepath.Join(config.LogPath, "stack.log")
	stackFile, err := os.OpenFile(stackFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("无法打开 stack.log 文件: %v", err)
	}
	logger.stackFile = stackFile
	logger.stackLogger = log.New(stackFile, "", 0)

	return logger, nil
}

// rotateFile 根据当前日期创建或切换到新的日志文件
func (l *Logger) rotateFile() error {
	if !l.fileOutput {
		return nil
	}

	now := time.Now()
	day := now.Day()

	if day == l.currentDay {
		return nil
	}

	l.mu.Lock()
	defer l.mu.Unlock()

	if l.file != nil {
		l.file.Close()
	}

	dateStr := now.Format("2006-01-02")
	fileName := fmt.Sprintf("%s_%s.log", l.filePrefix, dateStr)
	filePath := filepath.Join(l.logPath, fileName)

	err := os.MkdirAll(filepath.Dir(filePath), 0755)
	if err != nil {
		return fmt.Errorf("无法创建日志目录: %v", err)
	}

	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return fmt.Errorf("无法打开日志文件: %v", err)
	}

	var writers []io.Writer
	writers = append(writers, file)
	writers = append(writers, os.Stdout)
	multiWriter := io.MultiWriter(writers...)
	l.logger = log.New(multiWriter, "", 0)
	l.file = file
	l.currentDay = day

	return nil
}

// log 内部日志记录函数
func (l *Logger) log(level LogLevel, format string, v ...interface{}) {
	if level < l.level {
		return
	}

	l.mu.Lock()
	defer l.mu.Unlock()

	if l.fileOutput {
		err := l.rotateFile()
		if err != nil {
			fmt.Printf("日志轮转失败: %v\n", err)
			return
		}
	}

	now := time.Now().Format("2006-01-02 15:04:05")
	msg := format
	args := v

	// 检查是否有 error 类型的参数
	for i, arg := range v {
		if err, ok := arg.(error); ok {
			// 使用与主日志相同的格式写入 stack.log
			_, file, line, _ := runtime.Caller(2)
			stackMsg := fmt.Sprintf("%s [%s] %s:%d: %v", now, levelNames[level], filepath.Base(file), line, err)
			l.stackLogger.Println(stackMsg)

			// 在日志消息中替换 error 为其字符串表示
			args[i] = err.Error()
		}
	}

	// 格式化消息
	msg = fmt.Sprintf(format, args...)

	logEntry := fmt.Sprintf("%s [%s] : %s", now, levelPrefix[level], msg)

	if l.fileOutput {
		l.logger.Println(logEntry)
	}

	if level == FATAL {
		os.Exit(1)
	}
}

// SetFileOutput 设置是否启用文件输出
func (l *Logger) SetFileOutput(enable bool) {
	l.mu.Lock()
	defer l.mu.Unlock()

	if l.fileOutput == enable {
		return
	}

	l.fileOutput = enable

	if enable {
		err := l.rotateFile()
		if err != nil {
			fmt.Printf("启用文件输出失败: %v\n", err)
			l.fileOutput = false
		}
	} else if l.file != nil {
		l.file.Close()
		l.file = nil
		l.logger = nil
	}
}

// SetLevel 设置日志级别
func (l *Logger) SetLevel(level LogLevel) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.level = level
}

// Debug 记录调试级别的日志
func (l *Logger) Debug(format string, v ...interface{}) {
	l.log(DEBUG, format, v...)
}

// Info 记录信息级别的日志
func (l *Logger) Info(format string, v ...interface{}) {
	l.log(INFO, format, v...)
}

// Warn 记录警告级别的日志
func (l *Logger) Warn(format string, v ...interface{}) {
	l.log(WARN, format, v...)
}

// Error 记录错误级别的日志
func (l *Logger) Error(format string, v ...interface{}) {
	l.log(ERROR, format, v...)
}

// Fatal 记录致命错误级别的日志，然后终止程序
func (l *Logger) Fatal(format string, v ...interface{}) {
	l.log(FATAL, format, v...)
}
